from scipy.sparse import lil_matrix
import logging
import os
from collections import Counter
import numpy as np

encoding_type = "utf-8"
split_sep = " "

class CorpusPreprocess(object):
    logger = logging.getLogger("CorpusPreprocess")
    def __init__(self, file_path, min_freq):
        self.file_path = file_path
        self.min_freq = min_freq
        self.vocab = Counter()
        self.cooccurrence_matrix = None
        self.idex2word = None
        self.word2idex = None
        self.nag_sampling_vocab = None
        self._build_vocab()
    def _read_data(self):
        if not os.path.exists(self.file_path):
            raise FileExistsError(f"file path {self.file_path} is not exist !")
        with open(self.file_path, "r", encoding = encoding_type) as f:
            for line in f:
                if line.strip():
                    yield line.strip().split(split_sep)

    def _build_cooccurrence_matrix(self, windows_size=5):
        if not self.vocab:
            self._build_vocab()
        self.cooccurrence_matrix = lil_matrix((len(self.vocab), len(self.vocab)), dtype=np.float32)
        for line in self._read_data():
            sentence_length = len(line)
            for i in range(sentence_length):
                center_w = line[i]
                if center_w not in self.vocab:
                    continue
                left_ws = line[max(i - windows_size, 0):i]
                # right_ws = line[i+1:min(len(line),i+1+windows_size)]

                # left cooccur
                for i, w in enumerate(left_ws[::-1]):
                    if w not in self.vocab:
                        continue
                    self.cooccurrence_matrix[self.vocab[center_w][0],
                                             self.vocab[w][0]] += 1.0 / (i + 1.0)
                    # cooccurrence_matrix is Symmetric Matrices
                    self.cooccurrence_matrix[self.vocab[w][0],
                                             self.vocab[center_w][0]] += 1.0 / (i + 1.0)

    def _build_vocab(self):
        for line in self._read_data():
            self.vocab.update(line)
        self.vocab = dict((w.strip(), f) for w,f in self.vocab.items() if (f >= self.min_freq and w.strip()))
        self.vocab = dict(sorted(self.vocab.items(), key=lambda x: x[1], reverse=True))
        self.vocab = {w:(i, f) for i, (w, f) in enumerate(self.vocab.items())}
        self.idex2word = {i:w for w, (i,f) in self.vocab.items()}
        self.logger.info("build vocab complete!")

    def get_cooccurrence_matrix(self, windows_size):
        if self.cooccurrence_matrix == None:
            self._build_cooccurrence_matrix(windows_size)
        return self.cooccurrence_matrix


    def get_vocab(self):
        if not isinstance(self.vocab, dict):
            self._build_vocab()
        return self.vocab